/*******************************
 * 利用events对WebSocketClient类进行的一个封装，目的是为了能够在浏览器环境下使用emit等api，顺利与master.js进行通信
 * 适用于使用ES6标准编写的前端工程
 * Author: Qogir
*******************************/
import { EventEmitter } from 'events';
import { w3cwebsocket as WebSocket } from 'websocket';

export default class WebSocketClient {
  constructor(url='ws://127.0.0.1:5000') {
    this.temperature = 100;
    this.url = url;
    this.ws = new WebSocket(this.url);
    this.ee = new EventEmitter();
    // attach message function as event listener for incoming websocket messages.
    this.ws.onmessage = this.message.bind(this);
    // attach message function as event listener for incoming websocket messages.
    this.ws.onopen = this.open.bind(this);
    // attache close function as listener on websocket disconnections.
    this.ws.onclose = this.close.bind(this);
    // attache error function as listener on websocket errors.
    this.ws.onerror = this.error.bind(this);

    this.on('connect', (socket) => {
      console.log('Server connect.');

      this.timerSendStatus = setInterval(() => {
        this.send({
          event: 'status',
          data: {
            temperature: this.temperature
          }
        })
      }, 1000);

      this.on('close', (code, desc) => {
        console.log('Connection closed ' + code + ': ' + desc);
        clearInterval(this.timerSendStatus);
      });

      this.on('message', (message) => {
        if (message.type === 'utf8') {
          const ev = JSON.parse(message.utf8Data)
          this.ee.emit('m:' + ev['event'], ev['data'], socket)
        }
      });

      this.on('m:status', (data) => {
        console.log('[status]' +
          ' cost:' + data['cost'] +
          ' mode:' + data['mode']
        );
      });

      this.on('m:interval', (data) => {
        interval = data['interval']
        clearInterval(this.timerSendStatus)
        this.timerSendStatus = setInterval(() => {
          this.ee.send(JSON.stringify({
            event: 'status',
            data: {
              temperature: this.temperature
            }
          }));
        }, interval);
        console.log('[interval]' +
          ' interval:', interval)
      });

      this.on('m:air', (data) => {
        console.log('[air]' +
          ' temperature:' + data['temperature'] +
          ' speed' + data['speed'])
      });

    });

    this.on('connectFailed', function (error) {
      console.log('Connect Error: ' + error.toString());
    });
  };

  send(obj) {
    try {
      this.ws.send(JSON.stringify(obj));
    } catch (e) {
      console.error('Error during send:', e);
    }
  }

  on(name, fn) {
    this.ee.on(name, fn);
  };

  open() {
    this.ee.emit('connect');
  };

  message(e) {
    try {
      const message = JSON.parse(e.data);
      this.ee.emit(`m:${message.event}`, message.data);
    }
    catch (err) {
      this.ee.emit('error', err);
      console.log(Date().toString() + ": ", err);
    }
  }

  emit(name, data) {
    const message = JSON.stringify({ name, data });
    this.ws.send(message);
  }

  close() {
    this.ws.close(); // close websocket connection
    this.ee.emit('close');
  };

  // error handles an error on a websocket.
  error(e) {
    console.log("websocket error: ", e);
  }
}
